package com.zsk.shop.service;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.github.wxpay.sdk.WXPayUtil;
import com.google.gson.Gson;
import com.zsk.shop.api.pay.ali.api.FundTransUniTransfer;
import com.zsk.shop.common.base.BaseResponse;
import com.zsk.shop.common.base.BizException;
import com.zsk.shop.common.base.BizExceptionEnum;
import com.zsk.shop.common.utils.DingTalkRootUtil;
import com.zsk.shop.common.utils.RedisUtil;
import com.zsk.shop.common.utils.ToolUtil;
import com.zsk.shop.config.interceptor.ErrorHandler;
import com.zsk.shop.config.pay.WeixinPayConfig;
import com.zsk.shop.entity.ShopOrder;
import com.zsk.shop.enums.EnumOrderInfo;
import com.zsk.shop.enums.EnumOrderStatus;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author Ys
 * @date 2022年03月01日 20:02
 */
@Slf4j
@Service
public class BasePayService {

    private static final Logger logger = LoggerFactory.getLogger(ShopOrderService.class);

    @Resource
    private ShopOrderService shopOrderService;
    @Resource
    private FundTransUniTransfer fundTransUniTransfer;
    @Resource
    private ShopUserService userService;
    @Resource
    private DingTalkRootUtil dingTalkRootUtil;
    @Resource
    private Environment environment;
    @Resource
    private ShopOrderPointsService shopOrderPointsService;


    /**
     * 主动查询订单状态 支付宝方式
     *
     * @return
     * @author Ys
     * @date 2021/4/27 9:25
     */
    public BaseResponse result(String orderNo) {
        try {
            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", environment.getProperty("pay.ali.app.appId"), environment.getProperty("pay.ali.app.keyPrivate"),"json","GBK",environment.getProperty("pay.ali.app.alipayPublicKey"),"RSA2");
            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("out_trade_no", orderNo);
            request.setBizContent(bizContent.toString());
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                if (ToolUtil.isEmpty(response.getTradeStatus())) {
                    return BaseResponse.error("该交易不存在");
                }
                return BaseResponse.success(response.getTradeStatus());
            } else {
                return BaseResponse.error(response.getTradeStatus());
            }
        } catch (Exception e) {
            return BaseResponse.error("支付失败");
        }
    }


    /**
     * 微信支付回调
     *
     * @return void
     * @author Ys
     * @date 2021/3/2 17:50
     */
    public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        //sb为微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
        Map<String, String> parameters = WXPayUtil.xmlToMap(notityXml);
        String returnCode = parameters.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
            //验证签名是否正确（根据订单信息重新获取签名）
            String sign = WXPayUtil.generateSignature(parameters, environment.getProperty("pay.weixin.js.key"));
            //根据微信官网的介绍，此处不仅对回调的参数进行验签，还需要对返回的金额与系统订单的金额进行比对等
            if (sign.equals(parameters.get("sign"))) {
                //订单号id
                String outTradeNo = parameters.get("out_trade_no");
                //微信支付订单号
                String transactionId = parameters.get("transaction_id");
                BigDecimal payAmount = new BigDecimal(parameters.get("total_fee")).divide(new BigDecimal(100));
                // 更改订单为已支付状态
                paySuccess(outTradeNo, payAmount, transactionId);
                logger.info("成功回调 outTradeNo==" + outTradeNo + ";/transactionId==" + transactionId);
                //通知微信服务器已经支付成功
                resXml = "<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> </xml>";
            } else {
                String outTradeNo = parameters.get("out_trade_no");
                payFail(outTradeNo);
                logger.info("微信支付回调失败!签名不一致");
            }
        } else {
            resXml = "<xml> <return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[报文为空]]></return_msg> </xml> ";
        }
        logger.info("微信支付回调数据结束");
        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }

    /**
     * 支付宝回调
     *
     * @return java.lang.String
     * @author Ys
     * @date 2021/3/2 12:36
     */
    public String aliPayNotify(HttpServletRequest request) {
        log.info("=========================原生支付宝开始回调=========================");
        Map<String, String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        log.info("支付回调参数======：" + new Gson().toJson(params));
        try {
            // 切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
            boolean flag = AlipaySignature.rsaCertCheckV1(params, environment.getProperty("pay.ali.app.aliPayPublicKeyCert"), "UTF-8", "RSA2");
            if (flag) {
                String tradeStatus = params.get("trade_status");
                String outTradeNo = params.get("out_trade_no");
                BigDecimal payAmount = new BigDecimal(params.get("total_amount"));
                if (tradeStatus.equals(EnumOrderInfo.ALI_TRADE_SUCCESS.getName())) {
                    paySuccess(outTradeNo, payAmount, null);
                    return "success";
                } else if (EnumOrderInfo.ALI_TRADE_CLOSED.getName().equals(tradeStatus)) {
                    payFail(outTradeNo);
                    return "fail";
                }
            }
        } catch (Exception e) {
            log.info("支付失败======：" + e);
            e.printStackTrace();
        }
        return "fail";
    }


    /**
     * 支付回调成功后更改订单状态
     *
     * @param tradeNo       订单号
     * @param totalAmount   支付金额
     * @param transactionId 微信支付订单号
     * @return void
     * @author Ys
     * @date 2021/11/22 15:40
     */
    public void paySuccess(String tradeNo, BigDecimal totalAmount, String transactionId) {
        logger.info("支付成功:开始回调11111=====tradeNo==" + tradeNo + "; totalAmount===" + totalAmount);
        ShopOrder order = shopOrderService.queryOnePayNot(tradeNo);
        try {
            if (ToolUtil.isEmpty(order)) {
                String orderNo = (String) RedisUtil.get("shop:" + tradeNo);
                order = shopOrderService.queryOnePayNot(orderNo);
            }
            if (ToolUtil.isNotEmpty(order)) {
                if(ToolUtil.isNotEmpty(order.getOrderPointsNo())){
                    shopOrderPointsService.updateOrderPoints(order.getOrderPointsNo(), order.getOrderNo());
                }
                order.setPayAmount(totalAmount);
                shopOrderService.updateOrderStatus(order.getOrderNo(), EnumOrderStatus.PAY_SUCCESS.getCode(), transactionId, totalAmount);
                // 添加积分列表
                shopOrderPointsService.saveShopOrderPoints(order);
                // 直推
                shopOrderService.addParentFirst(order);
                //变更会员
                if (order.getGoodsOrderType().equals(4)) {
                    userService.setVipUser(order.getUserNo(), order.getSnapshot());
                }
            }
        } catch (Exception e) {
            logger.error("支付成功订单状态扭转有误", e);
            dingTalkRootUtil.send("支付回调异常" + "异常信息" + e.getMessage() + "\n" + ErrorHandler.getExceptionText(e) + ",订单集合:" + order + ",,订单:" + order.getOrderNo() + ",原因：回调异常  操作：支付", "", false);
            throw new BizException(BizExceptionEnum.ERROR.getCode(), BizExceptionEnum.ERROR.getMessage());
        }
    }


    /**
     * 支付失败回调
     *
     * @param tradeNo 订单号
     * @return void
     * @author Ys
     * @date 2021/3/2 17:41
     */
    public void payFail(String tradeNo) {
        logger.info("支付失败:tradeNo==" + tradeNo);
        ShopOrder order = shopOrderService.queryOnePayNot(tradeNo);
        try {
            if (ToolUtil.isNotEmpty(order)) {

            }
        } catch (Exception e) {
            logger.error("支付成功订单状态扭转有误", e);
            dingTalkRootUtil.send("支付回调异常" + "异常信息" + e.getMessage() + "\n" + ErrorHandler.getExceptionText(e) + ",订单集合:" + order + ",,订单:" + order.getOrderNo() + ",原因：回调异常  操作：支付", "", false);
            throw new BizException(BizExceptionEnum.ERROR.getCode(), BizExceptionEnum.ERROR.getMessage());
        }
    }
}
